package face_engine_go

/*
#cgo CFLAGS	: -I./include
#cgo LDFLAGS: -larcsoft_face_engine
#include <stdlib.h>
#include "merror.h"
#include "asvloffscreen.h"
#include "arcsoft_face_sdk.h"
*/
import "C"

import "unsafe"
// FaceFeature 人脸特征结构体
type FaceFeature struct {
	Feature     []byte // 人脸特征信息
	FeatureSize int32  // 人脸特征信息长度
	native      *C.ASF_FaceFeature
	featurePtr  *C.MByte
}

// Release 释放内存
func (feature *FaceFeature) Release() {
	if feature.featurePtr != nil {
		C.free(unsafe.Pointer(feature.featurePtr))
	}
}

// EngineError SDK错误码
type EngineError struct {
	Code int
	Text string
}

// 实现Error接口
func (err EngineError) Error() string {
	return err.Text
}

func newError(code int, text string) EngineError {
	return EngineError{
		Code: code,
		Text: text,
	}
}

// FaceFeatureCompare 人脸特征比对
func (engine *FaceEngine) FaceFeatureCompare(feature1, feature2 FaceFeature) (confidenceLevel float32, err error) {
	r := C.ASFFaceFeatureCompare(engine.handle,
		feature1.native,
		feature2.native,
		(*C.MFloat)(unsafe.Pointer(&confidenceLevel)),
		//C.ASF_DETECT_MODEL_RGB,
	)
	if r != C.MOK {
		err = newError(int(r), "人脸特征比对失败!")
	}
	return
}
// SingleFaceInfo 单人脸信息结构体
type SingleFaceInfo struct {
	FaceRect   Rect  // 人脸框信息
	FaceOrient int32 // 输入图像的角度，可以参考 ArcFaceCompare_OrientCode
	DataInfo   C.ASF_FaceDataInfo
}

// FaceFeatureExtract 单人脸特征提取
func (engine *FaceEngine) FaceFeatureExtract(
	width int, // 宽度
	height int, // 高度
	format C.MInt32, // 图像格式
	imgData []byte, // 图片数据
	faceInfo SingleFaceInfo, // 单人脸信息
	registerOrNot int, // 图片模式
	mask int, // 是否带口罩
) (faceFeature FaceFeature, err error) {
	asfFaceFeature := &C.ASF_FaceFeature{}
	asfFaceInfo := &C.ASF_SingleFaceInfo{
		C.MRECT{
			C.MInt32(faceInfo.FaceRect.Left),
			C.MInt32(faceInfo.FaceRect.Top),
			C.MInt32(faceInfo.FaceRect.Right),
			C.MInt32(faceInfo.FaceRect.Bottom)},
		C.MInt32(faceInfo.FaceOrient),
		//faceInfo.DataInfo,
	}
	r := C.ASFFaceFeatureExtract(
		engine.handle,
		C.MInt32(width),
		C.MInt32(height),
		format,
		(*C.MUInt8)(unsafe.Pointer(&imgData[0])),
		asfFaceInfo,
		//C.ASF_RegisterOrNot(registerOrNot),
		//C.MInt32(mask),
		asfFaceFeature,
		)
	if r != C.MOK {
		return FaceFeature{}, newError(int(r), "提取人脸特征失败")
	}
	length := int32(asfFaceFeature.featureSize)
	faceFeature.FeatureSize = length
	faceFeature.Feature = make([]byte, length)
	byteArr := (*[1 << 12]byte)(unsafe.Pointer(asfFaceFeature.feature))[:length:length]
	arr := (*C.MByte)(C.malloc(C.size_t(int32(asfFaceFeature.featureSize))))
	faceFeature.featurePtr = arr
	ps := (*[1 << 12]C.MByte)(unsafe.Pointer(arr))[:length:length]
	for i := 0; i < len(ps); i++ {
		ps[i] = C.MByte(byteArr[i])
		faceFeature.Feature[i] = byteArr[i]
	}
	asfFaceFeature.feature = arr
	faceFeature.native = asfFaceFeature
	return faceFeature, err
}

// GetSingleFaceInfo 从多人脸结构体中提取单人脸信息
func GetSingleFaceInfo(multiFaceInfo MultiFaceInfo) (faceInfo []SingleFaceInfo) {
	faceInfo = make([]SingleFaceInfo, multiFaceInfo.FaceNum)
	for i := 0; i < len(faceInfo); i++ {
		faceInfo[i].FaceRect = Rect{
			Left:   multiFaceInfo.FaceRect[i].Left,
			Top:    multiFaceInfo.FaceRect[i].Top,
			Right:  multiFaceInfo.FaceRect[i].Right,
			Bottom: multiFaceInfo.FaceRect[i].Bottom,
		}
		faceInfo[i].FaceOrient = multiFaceInfo.FaceOrient[i]
		faceInfo[i].DataInfo = multiFaceInfo.FaceDataInfoList[i]
	}
	return
}

// ReadFaceFeatureFromBytes 将字节数据转为人脸特征数据
func ReadFaceFeatureFromBytes(bytes []byte) (feature FaceFeature) {
	asfFaceFeature := &C.ASF_FaceFeature{}
	arr := (*C.MByte)(C.malloc(C.size_t(int32(len(bytes)))))
	featurePtr := (*C.uchar)(unsafe.Pointer(C.CString(string(bytes))))
	asfFaceFeature.feature = featurePtr
	asfFaceFeature.featureSize = C.int(len(bytes))
	return FaceFeature{
		Feature:     bytes,
		FeatureSize: int32(len(bytes)),
		featurePtr:  arr,
		native:      asfFaceFeature,
	}
}

// MultiFaceInfo 多人脸信息结构体
type MultiFaceInfo struct {
	FaceRect         []Rect               // 人脸框信息
	FaceOrient       []int32              // 输入图像的角度
	FaceNum          int32                // 检测到的人脸个数
	FaceID           []int32              // face ID，IMAGE模式下不返回FaceID
	WearGlasses      float32              // 带眼镜置信度[0-1]，推荐阈值0.5
	LeftEyeClosed    int32                // 左眼状态 0 未闭眼 1 闭眼
	RightEyeClosed   int32                // 右眼状态 0 未闭眼 1 闭眼
	FaceDataInfoList []C.ASF_FaceDataInfo // 多张人脸信息
	native           *C.ASF_MultiFaceInfo
}
// DetectFaces 人脸检测，目前不支持IR图像数据检测
func (engine *FaceEngine) DetectFaces(
	width int, // 宽度
	height int, // 高度
	format C.MInt32, // 图像格式
	imgData []byte, // 图片数据
) (faceInfo MultiFaceInfo, err error) {
	asfFaceInfo := &C.ASF_MultiFaceInfo{}
	r := C.ASFDetectFaces(engine.handle,
		C.MInt32(width),
		C.MInt32(height),
		format,
		(*C.MUInt8)(unsafe.Pointer(&imgData[0])),
		asfFaceInfo,
		//C.ASF_DETECT_MODEL_RGB,
	)
	if r != C.MOK {
		return faceInfo, newError(int(r), "人脸检测失败")
	}
	faceNum := int32(asfFaceInfo.faceNum)
	faceInfo.FaceNum = faceNum
	if faceNum > 0 {
		faceInfo.FaceRect = (*[10]Rect)(unsafe.Pointer(asfFaceInfo.faceRect))[:faceNum:faceNum]
		faceInfo.FaceOrient = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceOrient))[:faceNum:faceNum]
	}
	if asfFaceInfo.faceID != nil {
		faceInfo.FaceID = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceID))[:faceNum:faceNum]
	}
	if asfFaceInfo.faceDataInfoList != nil {
		faceInfo.FaceDataInfoList = (*[10]C.ASF_FaceDataInfo)(unsafe.Pointer(asfFaceInfo.faceDataInfoList))[:faceNum:faceNum]
	}
	faceInfo.native = asfFaceInfo
	return
}